﻿using Microsoft.Win32;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Habi.Solver.Helpers
{
    public class SystemEnvHelper
    {
        public class Memory
        {
            #region 获得内存信息API
            [DllImport("kernel32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool GlobalMemoryStatusEx(ref MEMORY_INFO mi);

            //定义内存的信息结构
            [StructLayout(LayoutKind.Sequential)]
            public struct MEMORY_INFO
            {
                public uint dwLength; //当前结构体大小
                public uint dwMemoryLoad; //当前内存使用率
                public ulong ullTotalPhys; //总计物理内存大小
                public ulong ullAvailPhys; //可用物理内存大小
                public ulong ullTotalPageFile; //总计交换文件大小
                public ulong ullAvailPageFile; //总计交换文件大小
                public ulong ullTotalVirtual; //总计虚拟内存大小
                public ulong ullAvailVirtual; //可用虚拟内存大小
                public ulong ullAvailExtendedVirtual; //保留 这个值始终为0
            }
            #endregion

            #region 格式化容量大小
            /// <summary>
            /// 格式化容量大小
            /// </summary>
            /// <param name="size">容量（B）</param>
            /// <returns>已格式化的容量</returns>
            private static string FormatSize(double size)
            {
                double d = (double)size;
                int i = 0;
                while ((d > 1024) && (i < 5))
                {
                    d /= 1024;
                    i++;
                }
                string[] unit = { "B", "KB", "MB", "GB", "TB" };
                return (string.Format("{0} {1}", Math.Round(d, 2), unit[i]));
            }
            #endregion

            #region 获得当前内存使用情况
            /// <summary>
            /// 获得当前内存使用情况
            /// </summary>
            /// <returns></returns>
            public static MEMORY_INFO GetMemoryStatus()
            {
                MEMORY_INFO mi = new MEMORY_INFO();
                try
                {

                    mi.dwLength = (uint)System.Runtime.InteropServices.Marshal.SizeOf(mi);
                    GlobalMemoryStatusEx(ref mi);

                }
                finally
                {
                   
                }

                return mi;
            }
            #endregion

            #region 获得当前可用物理内存大小
            /// <summary>
            /// 获得当前可用物理内存大小
            /// </summary>
            /// <returns>当前可用物理内存（B）</returns>
            public static ulong GetAvailPhys()
            {
                MEMORY_INFO mi = GetMemoryStatus();
                return mi.ullAvailPhys;
            }
            #endregion

            #region 获得当前已使用的内存大小
            /// <summary>
            /// 获得当前已使用的内存大小
            /// </summary>
            /// <returns>已使用的内存大小（B）</returns>
            public static ulong GetUsedPhys()
            {
                MEMORY_INFO mi = GetMemoryStatus();
                return (mi.ullTotalPhys - mi.ullAvailPhys);
            }
            #endregion

            #region 获得当前总计物理内存大小
            /// <summary>
            /// 获得当前总计物理内存大小
            /// </summary>
            /// <returns&amp;gt;总计物理内存大小（B）&amp;lt;/returns&amp;gt;
            public static ulong GetTotalPhys()
            {
                MEMORY_INFO mi = GetMemoryStatus();
                return mi.ullTotalPhys;


            }
            #endregion
        }



        public class CPU
        {
            public double[] GetUsage()
            {
                return new double[] { 0.4 };
            }
        }



        public class App
        {

            private static List<AppRegInfo> GetInstallApps(RegistryKey key)
            {
                List<AppRegInfo> appModels = new List<AppRegInfo>();
                foreach (string keyName in key.GetSubKeyNames())
                {
                    RegistryKey subkey = key.OpenSubKey(keyName);
                    string displayName = subkey.GetValue("DisplayName") as string;
                    string displayIcon = subkey.GetValue("DisplayIcon") as string;
                    string installPath = subkey.GetValue("InstallLocation") as string;
                    string unInstallPath = subkey.GetValue("UninstallString") as string;
                    string displayVersion = subkey.GetValue("DisplayVersion") as string;
                    string publisher = subkey.GetValue("Publisher") as string;
                    string infoAbout = subkey.GetValue("URLInfoAbout") as string;

                    if (string.IsNullOrEmpty(displayName)) continue;

                    if (string.IsNullOrEmpty(installPath)) installPath = PathHelper.Get(unInstallPath);

                    appModels.Add(new AppRegInfo { DisplayIcon = displayIcon, DisplayName = displayName, InstallLocation = installPath, DisplayVersion = displayVersion, Publisher = publisher, URLInfoAbout = infoAbout, UninstallString = unInstallPath, InstallDate = DateTimeHelper.FromFileCreateTime(installPath) });
                }

                return appModels;
            }
            public static List<AppRegInfo> GetInstallApps()
            {
                List<AppRegInfo> appModels = new List<AppRegInfo>();

                try
                {
                    using (RegistryKey key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", false))
                    {
                        appModels.AddRange(GetInstallApps(key));
                    }
                    
                    using (var localMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
                    {
                        var key = localMachine.OpenSubKey(@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall", false);
                        appModels.AddRange(GetInstallApps(key));
                    }

                    using (var localMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
                    {
                        var key = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", false);
                        appModels.AddRange(GetInstallApps(key));
                    }

                    using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall", false))
                    {
                        appModels.AddRange(GetInstallApps(key));
                    }

                    return appModels;

                }
                catch (Exception)
                {
                    return appModels;
                }
            }
        }

        public class FileIcon
        {
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            public struct SHFILEINFO
            {
                public IntPtr hIcon;
                public int iIcon;
                public uint dwAttributes;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
                public string szDisplayName;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
                public string szTypeName;
            }
            [DllImport("Shell32.dll", EntryPoint = "SHGetFileInfo", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);

            [DllImport("User32.dll", EntryPoint = "DestroyIcon")]
            public static extern int DestroyIcon(IntPtr hIcon);
            #region API 参数的常量定义

            public enum FileInfoFlags : uint
            {
                SHGFI_ICON = 0x000000100,  //  get icon
                SHGFI_DISPLAYNAME = 0x000000200,  //  get display name
                SHGFI_TYPENAME = 0x000000400,  //  get type name
                SHGFI_ATTRIBUTES = 0x000000800,  //  get attributes
                SHGFI_ICONLOCATION = 0x000001000,  //  get icon location
                SHGFI_EXETYPE = 0x000002000,  //  return exe type
                SHGFI_SYSICONINDEX = 0x000004000,  //  get system icon index
                SHGFI_LINKOVERLAY = 0x000008000,  //  put a link overlay on icon
                SHGFI_SELECTED = 0x000010000,  //  show icon in selected state
                SHGFI_ATTR_SPECIFIED = 0x000020000,  //  get only specified attributes
                SHGFI_LARGEICON = 0x000000000,  //  get large icon
                SHGFI_SMALLICON = 0x000000001,  //  get small icon
                SHGFI_OPENICON = 0x000000002,  //  get open icon
                SHGFI_SHELLICONSIZE = 0x000000004,  //  get shell size icon
                SHGFI_PIDL = 0x000000008,  //  pszPath is a pidl
                SHGFI_USEFILEATTRIBUTES = 0x000000010,  //  use passed dwFileAttribute
                SHGFI_ADDOVERLAYS = 0x000000020,  //  apply the appropriate overlays
                SHGFI_OVERLAYINDEX = 0x000000040   //  Get the index of the overlay
            }
            public enum FileAttributeFlags : uint
            {
                FILE_ATTRIBUTE_READONLY = 0x00000001,
                FILE_ATTRIBUTE_HIDDEN = 0x00000002,
                FILE_ATTRIBUTE_SYSTEM = 0x00000004,
                FILE_ATTRIBUTE_DIRECTORY = 0x00000010,
                FILE_ATTRIBUTE_ARCHIVE = 0x00000020,
                FILE_ATTRIBUTE_DEVICE = 0x00000040,
                FILE_ATTRIBUTE_NORMAL = 0x00000080,
                FILE_ATTRIBUTE_TEMPORARY = 0x00000100,
                FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200,
                FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400,
                FILE_ATTRIBUTE_COMPRESSED = 0x00000800,
                FILE_ATTRIBUTE_OFFLINE = 0x00001000,
                FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000,
                FILE_ATTRIBUTE_ENCRYPTED = 0x00004000
            }
            #endregion
            /// <summary>
            /// 获取文件类型的关联图标
            /// </summary>
            /// <param name="fileName">文件类型的扩展名或文件的绝对路径</param>
            /// <param name="isLargeIcon">是否返回大图标</param>
            /// <returns>获取到的图标</returns>
            public static Icon GetIcon(string fileName, bool isLargeIcon)
            {
                SHFILEINFO shfi = new SHFILEINFO();
                IntPtr hI;

                if (isLargeIcon)
                    hI = SHGetFileInfo(fileName, 0, ref shfi, (uint)Marshal.SizeOf(shfi), (uint)FileInfoFlags.SHGFI_ICON | (uint)FileInfoFlags.SHGFI_USEFILEATTRIBUTES | (uint)FileInfoFlags.SHGFI_LARGEICON);
                else
                    hI = SHGetFileInfo(fileName, 0, ref shfi, (uint)Marshal.SizeOf(shfi), (uint)FileInfoFlags.SHGFI_ICON | (uint)FileInfoFlags.SHGFI_USEFILEATTRIBUTES | (uint)FileInfoFlags.SHGFI_SMALLICON);

                Icon icon = Icon.FromHandle(shfi.hIcon).Clone() as Icon;

                DestroyIcon(shfi.hIcon); //释放资源
                return icon;
            }
            /// <summary>  
            /// 获取文件夹图标
            /// </summary>  
            /// <returns>图标</returns>  
            public static Icon GetDirectoryIcon(bool isLargeIcon)
            {
                SHFILEINFO _SHFILEINFO = new SHFILEINFO();
                IntPtr _IconIntPtr;
                if (isLargeIcon)
                {
                    _IconIntPtr = SHGetFileInfo(@"", 0, ref _SHFILEINFO, (uint)Marshal.SizeOf(_SHFILEINFO), ((uint)FileInfoFlags.SHGFI_ICON | (uint)FileInfoFlags.SHGFI_LARGEICON));
                }
                else
                {
                    _IconIntPtr = SHGetFileInfo(@"", 0, ref _SHFILEINFO, (uint)Marshal.SizeOf(_SHFILEINFO), ((uint)FileInfoFlags.SHGFI_ICON | (uint)FileInfoFlags.SHGFI_SMALLICON));
                }
                if (_IconIntPtr.Equals(IntPtr.Zero)) return null;
                Icon _Icon = System.Drawing.Icon.FromHandle(_SHFILEINFO.hIcon);
                return _Icon;
            }
        }

        public class AppRegInfo
        {
            public string InstallLocation { get; set; }
            public string DisplayIcon { get; set; }
            public string DisplayName { get; set; }
            public string DisplayVersion { get; set; }
            public string Publisher { get; set; }
            public string UninstallString { get; set; }
            public string URLInfoAbout { get; set; }
            public DateTime? InstallDate { get; set; }
        }
    }
}
